require 'Qt4'
require 'date'
load 'databasetableslice.rb'

class DTConversions
	def self.integerToQTime(totalSeconds)
	   hours=totalSeconds.div(3600)
	   minutes=(totalSeconds % 3600).div(60)
	   seconds=totalSeconds % 60
	   result=Qt::Time.new( hours, minutes, seconds)
	   return result
	end
	
	def self.qtimeToInteger(time)
	    result=time.hour()*3600+time.minute()*60+time.second()
		return result
	end
	
	def self.qdateToDate(date)
	    ruby_date=Date.new(date.year,date.month,date.day)
		return ruby_date
	end
	
	def self.dateToQDate(date)
		result=Qt::Date.new(date.year,date.month,date.day)
		return result
	end
	
	def self.totalTimeToString(totalSeconds)
		hours=totalSeconds.div(3600)
	    minutes=(totalSeconds % 3600).div(60)
	    seconds=totalSeconds % 60
		return hours.to_s + ":" + minutes.to_s + ":" + seconds.to_s
	end
end
class WeekHours
	attr_accessor :firstFirstWeek   # First week date (QDate)
	attr_accessor :freeHours        # 2 of 7 QTime Structs
	
	def setFirstWeekMonday(day)
		qdate=day
		if (qdate.dayOfWeek()!=1)
			qdate.addDays( -1*(qdate.dayOfWeek()-1) )
		end
		@firstFirstWeek=DTConversions.qdateToDate(qdate)
		return qdate
	end
	
	def getFirstWeek()
		return DTConversions.dateToQDate(@firstFirstWeek)
	end
	
	def initialize()
		@freeHours = Array.new
		[0,1].each { 
			|x| 
			@freeHours[x]=Array.new
			[0,1,2,3,4,5,6].each { 
			|y| @freeHours[x][y]=23*3600+59*60+59  # 23, 59,59 
			}
		}
		@firstFirstWeek = Date.today
		if @firstFirstWeek.monday? == false
			@firstFirstWeek=@firstFirstWeek.prev_day(@firstFirstWeek.wday()-1)
		end
	end
	
	def getPivotWeek()
		return Qt::Date.new(@firstFirstWeek.day(),@firstFirstWeek.month(),@firstFirstWeek.year())
	end
	#Returns free hours amount, associated with dates in QTime format
	def getFreeHoursByWeekAndDay(week,day)  # week and day are number
	   totalSeconds = @freeHours[week][day]
	   return DTConversions::integerToQTime(totalSeconds)
	end
	def getFreeHoursAsQTime(date)
	    freeHoursAtDay=self.getFreeHours(date)
		return DTConversions::integerToQTime(freeHoursAtDay)
	end
	def getFreeHours(date)
	    #Compute current week
		ruby_date=DTConversions.qdateToDate(date)
		week=( (ruby_date-@firstFirstWeek)/7 ).to_i 
		result=@freeHours[week][ruby_date.wday()-1]
		return result
	end
	def setFreeHours(week,day,time)
	    @freeHours[week][day]=DTConversions::qtimeToInteger(time)
	end
	
end

class Database
	attr_accessor :targets
	attr_accessor :tasks
	
	attr_accessor :maxTargetIndex
	attr_accessor :maxTaskIndex
	
	attr_accessor :weekFreeHours
	
	def initialize()
		@targets = Array.new
		@tasks = Array.new
		@maxTargetIndex = 1
		@maxTaskIndex = 1
		@weekFreeHours = WeekHours.new
	end
	
	
	def getDatabaseTableSlice(date,show_all)
		result=DatabaseTableSlice.new()
		@tasks.each{ |x|
		  if (x.getExecutionRubyDate()==date) and ((show_all==true) or (x.getStatus()==true))
			result.addTask(self,x)
		  end
		}
		return result
	end
	
	def getSpentHoursAndWriteTarget(targetID,string_list,range)
		#totalTimeToString
		subtargets=self.getSubtargets(targetID,true)
		tasks=self.getTasks(targetID,true)
		total_time=0
		subtargets.each{ |x|
			total_time=total_time + self.getSpentHoursAndWriteTarget(x.getID(),string_list,range)
		}
		tasks.each{ |x|
		  date=DTConversions::qdateToDate(x.getExecutionDate())
		  if (range.include?(date)==true) and (x.getStatus()==false)
			total_time=total_time + x.getSpentTimeAsInteger()
		  end
		}
		if subtargets.count()==0
			string_list << ( self.getTarget(targetID).getName() ) + ";" + DTConversions::totalTimeToString(total_time)
		end
		return total_time
	end
	
	def getTotalExecutionTimeForADay(qdate)
		time=0
		@tasks.each{ 
		   |x|
		   if (x.getExecutionDate()==qdate)
		     time= time +  DTConversions::qtimeToInteger(x.getExecutionTime())
		   end
		}
		return time
	end
	
	def getWeeklyFreeHours()
		return @weekFreeHours
	end
	
	def createNewTarget(parent_index)
	    target=Target.new(parent_index,@maxTargetIndex)
		@maxTargetIndex=@maxTargetIndex+1
		@targets<<target
		return target
	end
	
	def createNewTask(parent_index)
		task=Task.new(parent_index,@maxTaskIndex)
		@maxTaskIndex=@maxTaskIndex+1
		@tasks<<task
		return task
	end
	
	def getTarget( targetID )
	    #print targetID
		index=@targets.index{ |x|  x.getID()==targetID }
		return @targets[index]
	end
	
	def deleteTarget ( targetID )
		@targets.delete_if{ |x| x.getID()==targetID }
	end
	
	def deleteTask( taskID )
		@tasks.delete_if{ |x| x.getID()==taskID }
	end
	
	def getSubtargets( targetID , all)
		result=Array.new
		@targets.each{ |x|
			if x.getParent()==targetID
			   if (all==false and  x.getStatus()==true) or (all==true) 
				result << x
			   end
			end
		}
		return result
	end
	
	def getTasks( targetID , all)
		result=Array.new
		@tasks.each{ |x|
			if x.getParent()==targetID
			   if (all==false and  x.getStatus()==true) or (all==true) 
				result << x
			   end
			end
		}
		return result
	end
	
	def load()
		begin
		file = File.open("database.report", "rb")
		contents = file.read
		
		db = Marshal.load(contents)
		@targets=db.targets
		@tasks=db.tasks
		@maxTargetIndex=db.maxTargetIndex
		@maxTaskIndex=db.maxTaskIndex
		@weekFreeHours=db.weekFreeHours
		rescue Errno::ENOENT => e
		end
	end
	
	def save()
		file=File.new("database.report","wb")
		if file.nil? == false
			file.write(Marshal.dump(self))
			file.close
		end
	end
end


class Target
    attr_accessor  :name   
    attr_accessor  :open
	attr_accessor  :parent #index (0 - for root)
	attr_accessor  :id     #id (index)
	
	def initialize(parent_index,id)
		@name="New target"
		@open=true
		@parent=parent_index
		@id=id
	end
	
	def getID()
		return @id
	end

	def setStatus(open)
		@open=open
	end
	def getStatus()
		return @open
	end
	
	def setName(name)
		@name=name
	end
	def getName()
		return @name
	end
	
	def getParent()
		return @parent
	end
	
end

class Task
	attr_accessor  :name   
    attr_accessor  :open
	attr_accessor  :parent #index (0 - for root)
	attr_accessor  :execution_date
	attr_accessor  :execution_time
	attr_accessor  :spent_time
	attr_accessor  :notice
	attr_accessor  :id
	
	
	def mustBeExecutedToday()
		result=false
		if @execution_date == Date.today
		  result=true
		end
		return result
	end
	def initialize(parent_index,id)
		@name="New task"
		@open=true
		@parent=parent_index
		@execution_date=Date.today
		@execution_time=3*3600 # Default time of execution is three hours
		@spent_time=0
		@notice=""
		@id=id
	end

	def getID()
		return @id
	end
	
	def setExecutionDate(qdate)
		@execution_date=DTConversions.qdateToDate(qdate)
	end
	def getExecutionRubyDate()
		return @execution_date
	end
	def getExecutionDate()
		result=DTConversions.dateToQDate(@execution_date)
		return result
	end
	def setExecutionTime(qtime)
		@execution_time=DTConversions.qtimeToInteger(qtime)
	end
	def getExecutionTime()
		result=DTConversions.integerToQTime(@execution_time)
		return result
	end
	def setSpentTime(qtime)
		@spent_time=DTConversions.qtimeToInteger(qtime)
	end
	def getSpentTime()
		result=DTConversions.integerToQTime(@spent_time)
		return result
	end
	
	def getSpentTimeAsInteger
		return @spent_time
	end

	def getNotice()
		return @notice
	end
	def setNotice(notice)
		@notice=notice
	end
	def getParent()
		return @parent
	end
	def setName(name)
		@name=name
	end
	def getName()
		return @name
	end
	def setStatus(open)
		@open=open
	end
	def getStatus()
		return @open
	end

end